#include <stdio.h>
#include "string.h"
#include "user.h"
#include <stdlib.h>

#define EXEC 1
#define REDIR 2
#define PIPE 3
#define LIST 4
#define BACK 5
#define MAXARGS 10

struct cmd {
	int type;
};
struct execcmd {
	int type;
	char *argv[MAXARGS];
	char *eargv[MAXARGS];
};

struct redircmd {
	int type;
	struct cmd *cmd;
	char *file;
	char *efile;
	int mode;
	int fd;
};

struct pipecmd {
	int type;
	struct cmd *left;
	struct cmd *right;
};

struct listcmd {
	int type;
	struct cmd *left;
	struct cmd *right;
};

struct backcmd {
	int type;
	struct cmd *cmd;
};
int fork1(void);
void panic(char*);
struct cmd *parsecmd(char*);
void runcmd(struct cmd *cmd)
{
	int p[2];
	struct backcmd *bcmd;
	struct execcmd *ecmd;
	struct listcmd *lcmd;
	struct pipecmd *pcmd;
	struct readircmd *rcmd;

	if(cmd == 0) exit(1);
	switch(cmd->type){
	default:
		panic("runcmd");
	case EXEC:
		ecmd = (struct execcmd*)cmd;
		if(ecmd->argv[0] == 0) exit(1);
		do_exec(ecmd->argv[0],ecmd->argv);
		printf("exec %s failed\n",ecmd->argv[0]);
		break;
	case REDIR:
		rcmd = (struct redircmd*)cmd;
		close(rcmd->fd);
		if(open(rcmd->file,rcmd->mode) < 0){
			printf("open %s failed\n",rcmd->file);
			exit(1)
		}
		runcmd(rcmd->cmd);
		break;
	case LIST:
		lcmd = (struct listcmd*)cmd;
		if(fork1() == 0)
			runcmd(lcmd->left);
		wait(0);
		runcmd(lcmd->right);
		break;
	case PIPE:
		pcmd = (struct pipecmd*)cmd;
		if(pipe(p) < 0)
			panic("pipe");
		if(fork1() == 0){
			do_close(0);
			dup(p[0]);
			do_close(p[0]);
			do_close(p[1]);
			runcmd(pcmd->left);
		}
		if(fork1() == 0){
			do_close(0);
			dup(p[0]);
			do_close(p[0]);
			do_close(p[1]);
			runcmd(pcmd->right);
		}
		do_close(p[0]);
		do_close(p[1]);
		wait(0);
		wait(0);
		break;
	case BACK:
		bcmd = (struct backcmd *)cmd;
		if(fork1() == 0)
			runcmd(bcmd->cmd);
		break;
	}
	exit(0);
}


void panic(char *s)
{
	printf("%s\n",s);
	exit(1);
}
int fork1()
{
	int pid;
	pid = fork();
	if(pid == -1) panic("fork");
	return pid;
}

int getcmd(char *buf, int nbuf)
{
  printf("$ ");
  memset(buf, 0, nbuf);
  gets(buf);
  if(buf[0] == 0) // EOF
    return -1;
  return 0;
}

int main(int argc, char **argv) {
    puts("user sh is running!!!");
    static char buf[100];
    int fd;

    // Read and run input commands.
    while(getcmd(buf, sizeof(buf)) >= 0){
        printf("buf %s\n",buf);

        if(buf[0] == 'c' && buf[1] == 'd' && buf[2] == ' '){
            // Chdir must be called by the parent, not the child.
            buf[strlen(buf)-1] = 0;  // chop \n
            if(chdir(buf+3) < 0)
            printf("cannot cd %s\n", buf+3);
               printf("cannot cd\n");
            continue;
        }
		if(fork1() == 0)
		//	runcmd(parsecmd(buf));
		wait(0);
    }
	exit(0);

    return 0;
}
